#pragma once

#include <iostream>
#include <memory>
#include<cstring>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <sys/wait.h>
#include <signal.h>
#include <thread>
#include <functional>

#include "Log.hpp"
#include "Comm.hpp"
#include "InetAddr.hpp"
#include "ThreadPool.hpp"

#define BACKLOG 8

uint16_t gport = 8080;
using namespace LogModule;
using namespace ThreadPoolModule;
using task_t = std::function<void(int)>;
using hander_t = std::function<std::string(std::string&)>;

class TcpServer
{
    struct ThreadData
    {
        int _sockfd;
        TcpServer* _self;
        ThreadData(int sockfd, TcpServer* self):_sockfd(sockfd),_self(self)
        {}
    };
public:
    TcpServer(hander_t hander, uint16_t port = gport):_hander(hander), _port(port), _isrunning(false)
    {}
    void InitServer()
    {
        //tcp传入SOCK_STREAM流，utp传入SOCK_DGRAM
        //1.创建流式套接字
        _listensockfd = ::socket(AF_INET, SOCK_STREAM, 0); //Tcp Socket
        if(_listensockfd < 0)
        {
            LOG(LogLevel::FATAL)<<"_sockfd error";
            DIE(SOCKET_ERR);
        }
        LOG(LogLevel::INFO)<<"socket create succeed, sockfd is:"<<_listensockfd;

        struct sockaddr_in local;
        memset(&local, 0, sizeof(local));
        local.sin_family = AF_INET;
        local.sin_port = htons(_port);
        local.sin_addr.s_addr = INADDR_ANY;

        //bind
        //2.绑定
        int n = ::bind(_listensockfd, (const sockaddr*)(&local), sizeof(local));
        if(n < 0)
        {
            LOG(LogLevel::FATAL)<<"bind error";
            DIE(BIND_ERR);
        }
        LOG(LogLevel::INFO)<<"bind succeed, sockfd:"<< _listensockfd;
        //监听
        //3.监听
        n = ::listen(_listensockfd, BACKLOG);
        if(n < 0)
        {
            LOG(LogLevel::FATAL)<<"listen error";
            DIE(LISTEN_ERR);
        }
        LOG(LogLevel::INFO)<<"listen succeed, sockfd:"<< _listensockfd;

        ::signal(SIGCHLD, SIG_IGN);//子进程退出，OS自动回收资源，不用wait
    }

    void HanderRequest(int sockfd)
    {
        LOG(LogLevel::INFO)<<"handerRequest succeed, sockfd:"<< sockfd;
        char inbuffer[4096];
        std::string package;
        while(1)
        {
            ssize_t n = recv(sockfd, inbuffer, sizeof(inbuffer)-1, 0); //recv读取不完整
            if(n>0)
            {
                inbuffer[n] = 0;
                LOG(LogLevel::INFO)<<inbuffer;
                package += inbuffer;

                std::string cmd_ret = _hander(package);
                if(cmd_ret.empty()) continue;

                ::send(sockfd, cmd_ret.c_str(), cmd_ret.size(), 0);
            }
            else if(n==0)
            {
                LOG(LogLevel::INFO)<<"client quit:"<<sockfd;
                break;
            }
            else{
                //读取失败
                break;
            }
        }
        ::close(sockfd);
    }
    //单线程特供
    static void ThreadEntry(ThreadData* data)
    {
        data->_self->HanderRequest(data->_sockfd);
    }
    void Start()
    {
        _isrunning = true;
        while(_isrunning)
        {
            //1.获取新连接
            struct sockaddr_in peer;
            //peerlen记得初始化
            socklen_t peerlen = sizeof(peer);
            int sockfd = ::accept(_listensockfd, (sockaddr*)(&peer), &peerlen);
            if(sockfd<0)
            {
                LOG(LogLevel::WARING)<<"accept error, sockfd "<<strerror(errno);
                //accept失败了，继续如下逻辑，不返回  
                continue;
            }
            //获取链接成功
            LOG(LogLevel::INFO)<<"accept succeed, sockfd:"<< sockfd;
            InetAddr addr(peer);
            LOG(LogLevel::INFO)<<"client info: "<<addr.Addr();

            //verson_0
            //HanderRequest(sockfd);

            //v1 多进程版本
            // pid_t id = fork();
            // if(id == 0)
            // {
            //     //child
            //     //子进程继承父进程文件描述符表，父子各一张
            //     //让子进程关闭不需要的fd
            //     ::close(_listensockfd);
            //     if(fork()>0)    exit(0);
            //     //孙子进程->儿子死了，变孤儿了->被系统领养
            //     HanderRequest(sockfd);
            //     exit(0);
            // }
            // ::close(sockfd);
            // int rid = ::waitpid(id, nullptr, 0);
            // if(rid < 0)
            // {
            //     LOG(LogLevel::WARING)<<"waitpid error";
            // }

            //v2 多线程版本
            //文件描述符表，被多线程共享
            // ThreadData* data = new ThreadData(sockfd, this);
            // std::thread t1(ThreadEntry, data);
            // t1.detach();

            //v3 线程池版本
            task_t func = std::bind(&TcpServer::HanderRequest, this, sockfd);
            ThreadPool<task_t>::GetInstance()->Equeue(func);
        }
    }
    void Stop()
    {
        _isrunning = false;
    }
    ~TcpServer()
    {}
private:
    int _listensockfd;
    int16_t _port;
    bool _isrunning;

    hander_t _hander;
};